package common.util;

import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author baolaiqiang
 * 综合了张哥使用的ip处理的工具类,添加了部分新的方法(主要新增加了对 ip/掩码位数  这种ip范围的处理)
 * ip地址转换博客 https://blog.csdn.net/whatday/article/details/79168699
 * 在线ip转换器 https://www.ab126.com/goju/1840.html
 */
public class IPUtil {

    /**
     * 用于判断是不是ip/掩码位数的正则表达式
     */
    private static final String IP_MASK_REGEX = "^(((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9]).){1}((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d).){2})((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)/(?:[1-9]|[12][0-9]|3[012])){1}$";

    public static void main(String[] args) {
        String ip = "192.168.0.1";
        System.out.println(isLegalIp(ip));
        System.out.println(ipToLong(ip));
        /**ip/掩码位数*/
        String ipAndMask = "192.168.1.1/31";
        String[] ipscope = getIpStrScope(ipAndMask);
        System.out.println(ipscope[0] + "--" + ipscope[1]);
        System.out.println(isIPRange(ipAndMask));
        String ipRange = "192.168.0.1-192.168.0.8";
        ip = ipAndMask;
        ip = ipRange;
        ip = "192.168.1.1/35";
        if (!IPUtil.isIP(ip) && !IPUtil.isIPRange(ip) && !IPUtil.isIpAndMask(ip)) {
            System.out.println(false);
        }
    }

    /**
     * 把192.168.1.1/24 转化为int数组范围
     *
     * @param ipAndMask
     * @return String[]
     */
    public static String[] getIpStrScope(String ipAndMask) {
        String[] ipArr = ipAndMask.split("/");
        if (ipArr.length != 2) {
            throw new IllegalArgumentException("invalid ipAndMask with: "
                    + ipAndMask);
        }
        int netMask = Integer.valueOf(ipArr[1].trim());
        if (netMask < 0 || netMask > 31) {
            throw new IllegalArgumentException("invalid ipAndMask with: "
                    + ipAndMask);
        }
        String startIp = getBeginIpStr(ipArr[0], netMask + "");
        String endIp = getEndIpStr(ipArr[0], netMask + "");
        return new String[]{startIp, endIp};
    }

    /**
     * 根据掩码位获取掩码
     *
     * @param maskBit 掩码位数，如"28"、"30"
     * @return
     */
    public static String getMaskByMaskBit(String maskBit) {
        return "".equals(maskBit) ? "error, maskBit is null !" : getMaskMap(maskBit);
    }

    /**
     * 根据 ip/掩码位 计算IP段的起始IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 起始IP的字符串表示
     */
    public static String getBeginIpStr(String ip, String maskBit) {
        return getIpFromLong(getBeginIpLong(ip, maskBit));
    }

    /**
     * 根据 ip/掩码位 计算IP段的起始IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 起始IP的长整型表示
     */
    public static Long getBeginIpLong(String ip, String maskBit) {
        return getIpFromString(ip) & getIpFromString(getMaskByMaskBit(maskBit));
    }

    /**
     * 根据 ip/掩码位 计算IP段的终止IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 终止IP的字符串表示
     */
    public static String getEndIpStr(String ip, String maskBit) {
        return getIpFromLong(getEndIpLong(ip, maskBit));
    }

    /**
     * 根据 ip/掩码位 计算IP段的终止IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 终止IP的长整型表示
     */
    public static Long getEndIpLong(String ip, String maskBit) {
        return getBeginIpLong(ip, maskBit)
                + ~getIpFromString(getMaskByMaskBit(maskBit));
    }

    /**
     * 把long类型的Ip转为一般Ip类型：xx.xx.xx.xx
     *
     * @param ip
     * @return
     */
    public static String getIpFromLong(Long ip) {
        String s1 = String.valueOf((ip & 4278190080L) / 16777216L);
        String s2 = String.valueOf((ip & 16711680L) / 65536L);
        String s3 = String.valueOf((ip & 65280L) / 256L);
        String s4 = String.valueOf(ip & 255L);
        return s1 + "." + s2 + "." + s3 + "." + s4;
    }

    /**
     * 把xx.xx.xx.xx类型的转为long类型的
     *
     * @param ip
     * @return
     */
    public static Long getIpFromString(String ip) {
        Long ipLong = 0L;
        String ipTemp = ip;
        ipLong = ipLong * 256
                + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf('.')));
        ipTemp = ipTemp.substring(ipTemp.indexOf('.') + 1, ipTemp.length());
        ipLong = ipLong * 256
                + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf('.')));
        ipTemp = ipTemp.substring(ipTemp.indexOf(".") + 1, ipTemp.length());
        ipLong = ipLong * 256
                + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf('.')));
        ipTemp = ipTemp.substring(ipTemp.indexOf('.') + 1, ipTemp.length());
        ipLong = ipLong * 256 + Long.parseLong(ipTemp);
        return ipLong;
    }


    /**
     * 判断ip地址是否合法
     */
    public static boolean isLegalIp(String text) {
        if (text != null && !text.isEmpty()) {
            // 定义正则表达式
            String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." +
                    "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." +
                    "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." +
                    "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
            // 判断ip地址是否与正则表达式匹配
            if (text.matches(regex)) {
                // 返回判断信息
                return true;
            } else {
                // 返回判断信息
                return false;
            }
        }
        return false;
    }

    /**
     * 判断是否是ip
     */
    public static boolean isIP(String addr) {
        final String REGX_IP = "((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
        if (addr.matches(REGX_IP)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断是否ip范围
     */
    public static boolean isIPRange(String range) {
        final String REGX_IP = "((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
        final String REGX_IPB = REGX_IP + "\\-" + REGX_IP;
        if (range.matches(REGX_IPB)) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否是 ip/掩码位数
     */
    public static boolean isIpAndMask(String ipAndMask) {
        Matcher m = Pattern.compile(IP_MASK_REGEX).matcher(ipAndMask);
        if (m.find()) {
            return true;
        }
        return false;
    }


    /**
     * 将ip地址转化为long类型
     */
    public static long ipToLong(String strIp) {
        long[] ip = new long[4];
        //先找到IP地址字符串中.的位置
        int position1 = strIp.indexOf(".");
        int position2 = strIp.indexOf(".", position1 + 1);
        int position3 = strIp.indexOf(".", position2 + 1);
        //将每个.之间的字符串转换成整型
        ip[0] = Long.parseLong(strIp.substring(0, position1));
        ip[1] = Long.parseLong(strIp.substring(position1 + 1, position2));
        ip[2] = Long.parseLong(strIp.substring(position2 + 1, position3));
        ip[3] = Long.parseLong(strIp.substring(position3 + 1));
        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
    }


    public static String getIpAddr(HttpServletRequest request) {
        //终端ip（说明通过代理方式访问,这里是客户机真实ip地址）
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            //代理机器ip地址
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();   //访问网站的节点  
        }

//        ip = request.getRemoteAddr();   //访问网站的节点  

        return ip;
    }

    public static String getRemoteIpAddr(HttpServletRequest request) {
        String ip = request.getRemoteAddr();
        return ip;
    }


    public static boolean isIPInRange(String ip, String range) {

        if (range != null && !range.equals("")) {
            String[] ranges = range.trim().replace("\r", "").split("\n");
            for (int i = 0; i < ranges.length; i++) {
                if (ipIsInNet(ranges[i], ip)) {
                    return true;
                }
            }
        }
        return false;
    }


    public static boolean ipIsInNet(String iparea, String ip) {
        if (iparea == null || ip == null)
            return false;
        iparea = iparea.trim();
        ip = ip.trim();
        final String REGX_IP = "((25[0-5]|2[0-4]//d|1//d{2}|[1-9]//d|//d)//.){3}(25[0-5]|2[0-4]//d|1//d{2}|[1-9]//d|//d)";
        final String REGX_IPB = REGX_IP + "//-" + REGX_IP;
        if (!iparea.matches(REGX_IPB) || !ip.matches(REGX_IP))
            return false;
        int idx = iparea.indexOf('-');
        String[] sips = iparea.substring(0, idx).split("/src/common/util/IPUtil.java");
        String[] sipe = iparea.substring(idx + 1).split("/src/common/util/IPUtil.java");
        String[] sipt = ip.split("/src/common/util/IPUtil.java");
        long ips = 0L, ipe = 0L, ipt = 0L;
        for (int i = 0; i < 4; ++i) {
            ips = ips << 8 | Integer.parseInt(sips[i]);
            ipe = ipe << 8 | Integer.parseInt(sipe[i]);
            ipt = ipt << 8 | Integer.parseInt(sipt[i]);
        }
        if (ips > ipe) {
            long t = ips;
            ips = ipe;
            ipe = t;
        }
        return ips <= ipt && ipt <= ipe;
    }

    /**
     * 根据mask位数反应相关的
     */
    public static String getMaskMap(String maskBit) {
        if ("1".equals(maskBit)) {
            return "128.0.0.0";
        }
        if ("2".equals(maskBit)) {
            return "192.0.0.0";
        }
        if ("3".equals(maskBit)) {
            return "224.0.0.0";
        }
        if ("4".equals(maskBit)) {
            return "240.0.0.0";
        }
        if ("5".equals(maskBit)) {
            return "248.0.0.0";
        }
        if ("6".equals(maskBit)) {
            return "252.0.0.0";
        }
        if ("7".equals(maskBit)) {
            return "254.0.0.0";
        }
        if ("8".equals(maskBit)) {
            return "255.0.0.0";
        }
        if ("9".equals(maskBit)) {
            return "255.128.0.0";
        }
        if ("10".equals(maskBit)) {
            return "255.192.0.0";
        }
        if ("11".equals(maskBit)) {
            return "255.224.0.0";
        }
        if ("12".equals(maskBit)) {
            return "255.240.0.0";
        }
        if ("13".equals(maskBit)) {
            return "255.248.0.0";
        }
        if ("14".equals(maskBit)) {
            return "255.252.0.0";
        }
        if ("15".equals(maskBit)) {
            return "255.254.0.0";
        }
        if ("16".equals(maskBit)) {
            return "255.255.0.0";
        }
        if ("17".equals(maskBit)) {
            return "255.255.128.0";
        }
        if ("18".equals(maskBit)) {
            return "255.255.192.0";
        }
        if ("19".equals(maskBit)) {
            return "255.255.224.0";
        }
        if ("20".equals(maskBit)) {
            return "255.255.240.0";
        }
        if ("21".equals(maskBit)) {
            return "255.255.248.0";
        }
        if ("22".equals(maskBit)) {
            return "255.255.252.0";
        }
        if ("23".equals(maskBit)) {
            return "255.255.254.0";
        }
        if ("24".equals(maskBit)) {
            return "255.255.255.0";
        }
        if ("25".equals(maskBit)) {
            return "255.255.255.128";
        }
        if ("26".equals(maskBit)) {
            return "255.255.255.192";
        }
        if ("27".equals(maskBit)) {
            return "255.255.255.224";
        }
        if ("28".equals(maskBit)) {
            return "255.255.255.240";
        }
        if ("29".equals(maskBit)) {
            return "255.255.255.248";
        }
        if ("30".equals(maskBit)) {
            return "255.255.255.252";
        }
        if ("31".equals(maskBit)) {
            return "255.255.255.254";
        }
        if ("32".equals(maskBit)) {
            return "255.255.255.255";
        }
        return "-1";
    }

    public static String getDomain(HttpServletRequest request) {
        String remoteHost = request.getRequestURL().toString();
        URL url = null;
        try {
            url = new URL(remoteHost);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        String host = url.getHost();
        remoteHost = host;
        String S = remoteHost;
        String[] split = S.split("\\.");
        StringBuffer stringBuffer = new StringBuffer();
        if (split.length > 2) {
            for (int i = 0; i < split.length; i++) {
                if (i != 0) {
                    stringBuffer.append(split[i] + ".");
                }
            }
        }
        String domain = stringBuffer.toString().replace("/.", "");
        if (domain.endsWith(".")) {
            domain = domain.substring(0, domain.length() - 1);
        }
        return domain;
    }

}
